/****************************************************************************
 *
 *  3DSAMBM.C
 *
 *  (C) Copyright 1997 by Autodesk, Inc.
 *
 *  This program is copyrighted by Autodesk, Inc. and is licensed to you under
 *  the following conditions.  You may not distribute or publish the source
 *  code of this program in any form.  You may incorporate this code in object
 *  form in derivative works provided such derivative works are (i.) are de-
 *  signed and intended to work solely with Autodesk, Inc. products, and (ii.)
 *  contain Autodesk's copyright notice "(C) Copyright 1995 by Autodesk, Inc."
 *
 *  AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  AUTODESK SPE-
 *  CIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 *  A PARTICULAR USE.  AUTODESK, INC.  DOES NOT WARRANT THAT THE OPERATION OF
 *  THE PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE.
 *
 ***************************************************************************/

#include <malloc.h>
#include <stdlib.h>
#include <string.h>

#include "3DSTYPE.H"
#include "3DSPRIM.H"
#include "3DSERR.H"
#include "CHUNKINF.H"
#include "CHUNK3DS.H"
#include "3DSFTKST.H"
#include "3DSSPTM.H"
#include "3DSAMBM.H"
#include "KFUTILS.H"

static              /* const */ char3ds *kAmbientName = "$AMBIENT$";

/*----------------------------------------------------------
  |
  |InitAmbientLightMotion3ds
  |
  +----------------------------------------------------------*/
void InitAmbientLightMotion3ds(kfambient3ds **light, 
                   ulong3ds nckeys)
{
  ulong3ds i;

  if (*light == NULL)
    {
      (*light) = malloc(sizeof(kfambient3ds));
      if(*light == NULL) 
    SET_ERROR_RETURN(ERR_NO_MEM);


      (*light)->flags1 = (*light)->flags2 = (ushort3ds)0;
      (*light)->nckeys  = nckeys;
      (*light)->color = NULL;
      (*light)->ckeys = NULL;
    }

  if ((*light)->ckeys != NULL) {
    free((*light)->ckeys); 
    (*light)->ckeys = NULL;
  }
  if ((*light)->color != NULL) {
    free((*light)->color); 
    (*light)->color = NULL;
  }

  if (nckeys != 0)
    {
      (*light)->ncflag = TrackSingle3ds;
      (*light)->nckeys = nckeys;

      (*light)->ckeys = calloc((*light)->nckeys, sizeof(keyheader3ds));
      if((*light)->ckeys == NULL) 
    SET_ERROR_RETURN(ERR_NO_MEM);

      for (i = 0; i < (*light)->nckeys; i++)
    memcpy(&(((*light)->ckeys)[i]), 
           &DefKeyHeader3ds, 
           sizeof(DefKeyHeader3ds));

      (*light)->color   = calloc((*light)->nckeys, sizeof(fcolor3ds));
      if((*light)->color == NULL) 
    SET_ERROR_RETURN(ERR_NO_MEM);

      for (i = 0; i < (*light)->nckeys; i++)
    ((*light)->color)[i].r = 
      ((*light)->color)[i].g = 
        ((*light)->color)[i].b = (float3ds)1.0;
    }
}

/*----------------------------------------------------------
|
 |ReleaseAmbientLightMotion3ds
 |
 +----------------------------------------------------------*/
void ReleaseAmbientLightMotion3ds(kfambient3ds **light)
{
   if (*light != NULL) {
      if((*light)->ckeys != NULL) 
      free((*light)->ckeys);
      if((*light)->color != NULL) 
      free((*light)->color);
      free(*light);
      *light = NULL;
  }
}


/*----------------------------------------------------------------------
 |
 | GetAmbientLightMotion3ds
 |
 |  db: database to be searched
 |  kfambient: Ptr to the addr of kfambient3ds structure, if (*kfambient) 
 |         is null, then memory will be allocated for the new
 |         structure, otherwise, the existing structure will be 
 |         filled in with the new values.  If no match is found, then
 |         kfambient remains unchanged.
 | 
 | Ambient light a special case: only one ambient node per keyframe data
 |    chunk.
 | 
 +----------------------------------------------------------------------*/
void GetAmbientLightMotion3ds(database3ds *db, 
                  kfambient3ds **kfambient)
{
  chunk3ds *pKfChunk, *pChunk = NULL;
  
  if(db == NULL) 
    SET_ERROR_RETURN(ERR_INVALID_ARG);

  /*--- Find Keyframe chunk */
  FindChunk3ds(db->topchunk, KFDATA, &pKfChunk);
  if (pKfChunk){
    FindChunk3ds(pKfChunk, AMBIENT_NODE_TAG, &pChunk);
    if (pChunk)
      GetAmbientLightMotionChunk3ds(pChunk, kfambient);
  }
}

/*--------------------------------------------------------------------------
 | GetAmbientLightMotionChunk3ds
 | 
 | pAmbientChunk:SPOTAMBIENT_NODE_TAG chunk to extract data from
 | pTargetChunk: L_TARGET_NODE_TAG chunk to extract target data from
 | kfspot: Structure to fill in with chunk data
 |
 |  chunk----->kfAmbient3ds
 |
 | Gets AmbientLight keyframe information from chunk
 | 
 |  L_TARGET
 |   ...
 |  NODE_HDR
 |  APP_DATA
 |  COL_TRACK
 | 
 +--------------------------------------------------------------------------*/
void GetAmbientLightMotionChunk3ds(chunk3ds *pAmbientChunk,
               kfambient3ds **kfambient)
{
    kfambient3ds 
    *pKfAmbient;
    chunk3ds 
    *pNodeHdrChunk, *pColChunk;
    ulong3ds i,
    nColKeys = 0;
    NodeHdr
    *pNodeHdr = NULL;
    ColTrackTag
    *pColData = NULL;
    
    if (pAmbientChunk == NULL)
      SET_ERROR_RETURN(ERR_INVALID_ARG); 
    
    /*-------------------------------
      |  Get information from chunks 
      +-------------------------------*/
    /*--- Search children of AmbientLight chunk */
    FindChunk3ds(pAmbientChunk, NODE_HDR, &pNodeHdrChunk);
    FindChunk3ds(pAmbientChunk, COL_TRACK_TAG, &pColChunk);

    if (pNodeHdrChunk){
      ReadChunkData3ds(pNodeHdrChunk);
      pNodeHdr = pNodeHdrChunk->data;
    }
    
    if(pColChunk){
    ReadChunkData3ds(pColChunk);
    pColData = pColChunk->data;
    nColKeys = pColData->trackhdr.keycount;
    }
    
    /*--------------------------------------------
      | Set-up and fill-in the kfambient3ds structure 
      +--------------------------------------------*/
    InitAmbientLightMotion3ds(kfambient, nColKeys); 
    
    pKfAmbient = *kfambient;
    
    /*--- Header Information */
    if (pNodeHdr){
      pKfAmbient->flags1 = pNodeHdr->flags1;
      pKfAmbient->flags2 = pNodeHdr->flags2;
    }

    /*--- Color Information */    
    if (pColData){
      if (nColKeys){
    pKfAmbient->ncflag = pColData->trackhdr.flags;
    for(i=0; i<nColKeys; i++){
      memcpy(&((pKfAmbient->ckeys)[i]), 
         &((pColData->keyhdrlist)[i]),
         sizeof(keyheader3ds));
      memcpy(&((pKfAmbient->color)[i]),
         &((pColData->colorlist)[i]),
         sizeof(fcolor3ds));
    }
      }
    }
    
    /*--- Free Chunk Data */
    if (pNodeHdrChunk)
    FreeFileChunkData3ds(pNodeHdrChunk);
    if (pColChunk)
    FreeFileChunkData3ds(pColChunk);
}

/*--------------------------------------------------------------------------
 | PutAmbientLightMotion3ds
 | Puts AmbientLight keyframe information into database. 
 | 
 |  kfAmbientLight3ds--->db
 |
 | KFDATA
 |  ...
 |  LIGHT_NODE
 |   NODE_ID
 |   NODE_HDR
 |   APP_DATA 
 |   COL_TRACK 
 |
 | Needs Work:
 |   1. NodeId: what value?
 |
 +--------------------------------------------------------------------------*/
void PutAmbientLightMotion3ds(database3ds *db, kfambient3ds *kfambient)
{
  chunk3ds 
    *pKfChunk, *pAmbientChunk, *pAmbientXdata = NULL;
    
  if(db == NULL || kfambient == NULL)
    SET_ERROR_RETURN(ERR_INVALID_ARG); 

  if(db->topchunk == NULL) 
    SET_ERROR_RETURN(ERR_INVALID_DATA);
    
  if (!(db->topchunk->tag == M3DMAGIC || db->topchunk->tag == CMAGIC))
    SET_ERROR_RETURN(ERR_WRONG_DATABASE);
    
  /*--- Find KFSEG chunk to put keyframe data into */
  kfGetKfSeg(db->topchunk, &pKfChunk);

  /*--- Destroy old chunks, Copy any XData and reattach it later */
  kfExtractXdata(db, kAmbientName, AMBIENT_NODE_TAG, &pAmbientXdata);
    
  pAmbientChunk = kfPutGenericNode(AMBIENT_NODE_TAG, pKfChunk);
  kfPutNodeId(pAmbientChunk);
  kfPutNodeHeader(kAmbientName,
          kfambient->flags1,
          kfambient->flags2,
          (char3ds *)0,
          pAmbientChunk);
    
  if (kfambient->nckeys>0 && kfambient->ckeys && kfambient->color)
    kfPutColorTrack(kfambient->nckeys,
            kfambient->ncflag,
            kfambient->ckeys,
            kfambient->color,
            pAmbientChunk);
    
  /*--- Replace XData */
  if (pAmbientXdata)
    AddChildOrdered3ds(pAmbientChunk, pAmbientXdata);
}

void DeleteAmbientLightMotion3ds(database3ds *db)
{
   DeleteNodeTagByNameAndType3ds(db, kAmbientName, AMBIENT_NODE_TAG);
   ON_ERROR_RETURN;
}

void CopyAmbientLightMotion3ds(database3ds *destdb, database3ds *srcdb)
{
   CopyNodeTagByNameAndType3ds(destdb, srcdb, kAmbientName, AMBIENT_NODE_TAG);
   ON_ERROR_RETURN;
}

